package com.godGuang.patient.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.godGuang.common.core.domain.Result;
import com.godGuang.common.core.utils.StringUtils;
import com.godGuang.common.security.service.TokenService;
import com.godGuang.patient.feign.FileControllerFeign;
import com.godGuang.patient.mapper.ArchivesMapper;
import com.godGuang.patient.mapper.FollowMapper;
import com.godGuang.patient.mapper.ImagesMapper;
import com.godGuang.patient.service.ArchivesService;
import com.patient.domin.Archives;
import com.patient.domin.FollowDoctor;
import com.patient.domin.Images;
import com.patient.domin.request.DoctorRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Service业务层处理
 *
 * @author godGuang
 * @date 2024-01-08
 */
@Service
@Slf4j
public class ArchivesServiceImpl implements ArchivesService
{
    private final FileControllerFeign feignClient;;

    private final ImagesMapper imagesMapper;

    private final FollowMapper followMapper;

    private final TokenService tokenService;

    private final RedisTemplate<String , String> redisTemplate;

    private final ArchivesMapper archivesMapper;

    private static final Integer ACTIVE_STATUS = 1;
    private static final Integer ACTIVE_NONE_STATUS = 0;

    public ArchivesServiceImpl(ArchivesMapper archivesMapper, @Qualifier("com.godGuang.patient.feign.FileControllerFeign") FileControllerFeign feignClient,
                               ImagesMapper imagesMapper, FollowMapper followMapper, TokenService tokenService,
                               RedisTemplate<String, String> redisTemplate) {
        this.archivesMapper = archivesMapper;
        this.feignClient = feignClient;
        this.imagesMapper = imagesMapper;
        this.followMapper = followMapper;
        this.tokenService = tokenService;
        this.redisTemplate = redisTemplate;
    }


    @Override
    public Archives selectSysArchivesList()
    {
        long o = System.currentTimeMillis();
        log.info("start time:{}" , o );
        Long userid = tokenService.getLoginUser().getUserid();
        if (redisTemplate.hasKey("archives"+userid)){
            String s = redisTemplate.opsForValue().get("archives" + userid);
            long l = System.currentTimeMillis();
            log.info("end time:{}" , (l - o ) );
            return JSON.parseObject(s, Archives.class);
        }
        Archives archives = archivesMapper.selectAll(userid);
        redisTemplate.opsForValue().set("archives"+userid, JSON.toJSONString(archives));
        long l = System.currentTimeMillis();
        log.info("end time:{}" , (l - o) );
        return archives;
    }

    @Override
    @Transactional
    public int insertSysArchives(Archives sysArchives)
    {
        Long userid = tokenService.getLoginUser().getUserid();
        sysArchives.setUserId(userid);
        int count = archivesMapper.insert(sysArchives);
        if (count > 0) { // 插入成功
            Long archivesId = sysArchives.getArchivesId();
            List<String> prices = sysArchives.getPrices();
            if (!CollectionUtils.isEmpty(prices)) {
                List<Images> imagesList = new ArrayList<>();
                for (String price : prices) {
                    Images images = new Images();
                    images.setImg(price);
                    images.setArchivesId(archivesId);
                    imagesList.add(images);
                }
                imagesMapper.batchInsert(imagesList);
            }
        }
        return count;
    }

    @Override
    public int updateArchives(Archives archives) {
        // 获取当前登录用户的id
        Long userId = tokenService.getLoginUser().getUserid();

        // 生成用于锁定的键名
        String lockKey = "lock:archives:" + userId;
        // 尝试获取锁
        Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked");
        // 设置锁的过期时间，防止锁一直占用
        redisTemplate.expire(lockKey, 10, TimeUnit.SECONDS);

        if (locked != null && locked) {
            try {
                // 加锁成功，执行需要保护的代码逻辑
        Long archivesId = archives.getArchivesId();
        // 添加查询条件，确保只有符合条件的记录才会被更新
        LambdaUpdateWrapper<Archives> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Archives::getArchivesId, archivesId);
        // 完整性校验，确保更新的数据不会缺失必要的字段或数据
        if (StringUtils.isBlank(archives.getMainSymptom())) {
            return Result.error("主要症状不能为空").getCode();
        }
        if (StringUtils.isBlank(archives.getNowIllness())) {
            return Result.error("现病史不能为空").getCode();
        }
        if (StringUtils.isBlank(archives.getOldIllness())) {
            return Result.error("既往病史不能为空").getCode();
        }
        if (StringUtils.isBlank(archives.getLatelyHeal())) {
            return Result.error("最近治疗不能为空").getCode();
        }
        if (StringUtils.isBlank(archives.getHealCourse())) {
            return Result.error("治疗过程不能为空").getCode();
        }

        updateWrapper.set(Archives::getMainSymptom, archives.getMainSymptom())
                .set(Archives::getNowIllness, archives.getNowIllness())
                .set(Archives::getOldIllness, archives.getOldIllness())
                .set(Archives::getLatelyHeal, archives.getLatelyHeal())
                .set(Archives::getStartHeal, archives.getStartHeal())
                .set(Archives::getEndHeal, archives.getEndHeal())
                .set(Archives::getHealCourse, archives.getHealCourse()
                );
                Long userid = tokenService.getLoginUser().getUserid();
                if (redisTemplate.hasKey("archives"+userid)){
            redisTemplate.delete("archives"+userid);
            redisTemplate.opsForValue().set("archives"+userid, JSON.toJSONString(archives));
        }
        int count = archivesMapper.update(null, updateWrapper);
        if (count > 0) { // 编辑成功
            List<String> prices1 = archives.getPrices();
            if (ObjectUtils.isNotEmpty(prices1)) {
                // 先删除原来的图片记录
                LambdaQueryWrapper<Images> deleteWrapper = new LambdaQueryWrapper<>();
                deleteWrapper.eq(Images::getArchivesId, archivesId);
                imagesMapper.delete(deleteWrapper);
                    for (String price : prices1) {
                        Images images = new Images();
                        images.setImg(price);
                        images.setArchivesId(archivesId);
                        imagesMapper.insert(images);
                    }
            }
        }

        if (count == 0){
            return Result.error("更新失败").getCode();
        }

        return Result.success(count,"更新成功").getCode();
            } finally {
                // 释放锁
                redisTemplate.delete(lockKey);
            }
        } else {
            // 获取锁失败，说明有其他线程正在执行该代码逻辑
            return Result.error("更新操作正在进行中，请稍后重试").getCode();
        }
    }


    @Override
    public Archives selectInfoId(Long archivesId) {
        Long userId = tokenService.getLoginUser().getUserid();
        String key = "archives" + userId;
        if (!redisTemplate.hasKey(key)) {
            return null;  // 缓存未命中，返回空对象或者 null
        }
        String value = redisTemplate.opsForValue().get(key);
        if (value == null) {
            return null;  // 处理返回值为 null 的情况
        }
        Archives archives = JSON.parseObject(value, Archives.class);
        if (!archives.getArchivesId().equals(archivesId)) {
            return null;  // 档案记录不匹配，返回空对象或者 null
        }
        return archives;
    }

    @Override
    public int remove(Long archivesId) {
        // 删除关联的图片记录
        LambdaQueryWrapper<Images> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(Images::getArchivesId, archivesId);
        imagesMapper.delete(deleteWrapper);

        Long userid = tokenService.getLoginUser().getUserid();
        // 删除 Redis 缓存
        redisTemplate.delete("archives"+userid);

        // 删除档案记录
        LambdaQueryWrapper<Archives> archivesLambdaQueryWrapper = new LambdaQueryWrapper<>();
        archivesLambdaQueryWrapper.eq(Archives::getArchivesId, archivesId);
        return archivesMapper.delete(archivesLambdaQueryWrapper);
    }

    @Override
    public void follow(DoctorRequest doctorRequest) {
        LambdaQueryWrapper<DoctorRequest> queryWrapper = new LambdaQueryWrapper<DoctorRequest>().eq(DoctorRequest::getDoctorId,
                doctorRequest.getDoctorId());
        long count = followMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new RuntimeException("已关注!");
        }

        DoctorRequest request = new DoctorRequest();
        request.setDoctorId(doctorRequest.getDoctorId());
        request.setUserId(tokenService.getLoginUser().getUserid());
        request.setFollowStatus(ACTIVE_STATUS);
        request.setCreatTime(new Date());
        request.setUpdateTime(null);

        followMapper.insert(request);
    }

    @Override
    public List<FollowDoctor> followList() {
        Long userId = tokenService.getLoginUser().getUserid();
        String key = "followDoctors:" + userId;
        int followStatus = ACTIVE_STATUS;
        List<FollowDoctor> followDoctors;

        if (redisTemplate.hasKey(key)){
            // 如果缓存存在，则直接从缓存中获取数据
            followDoctors = getFollowDoctorListFromRedis(key);
        } else {
            // 如果缓存不存在，则从数据库中获取数据，并将结果存储到Redis缓存中
            followDoctors = archivesMapper.followList(userId, followStatus);
            saveFollowDoctorListToRedis(key, followDoctors);
        }

        return followDoctors;
    }
    private List<FollowDoctor> getFollowDoctorListFromRedis(String key) {
        List<String> doctorJsonList = redisTemplate.opsForList().range(key, 0, -1);

        // 将JSON字符串转换为FollowDoctor对象列表
        List<FollowDoctor> followDoctors = new ArrayList<>();
        for (String doctorJson : doctorJsonList) {
            FollowDoctor doctor = JSON.parseObject(doctorJson, FollowDoctor.class);
            followDoctors.add(doctor);
        }

        return followDoctors;
    }
    private void saveFollowDoctorListToRedis(String key, List<FollowDoctor> followDoctors) {
        // 在存储到Redis缓存之前，先删除对应的键，以避免数据不一致
        redisTemplate.delete(key);

        // 将FollowDoctor对象列表转换为JSON字符串列表，并存储到Redis缓存中
        List<String> doctorJsonList = new ArrayList<>();
        for (FollowDoctor doctor : followDoctors) {
            String doctorJson = JSON.toJSONString(doctor);
            doctorJsonList.add(doctorJson);
        }
        redisTemplate.opsForList().leftPushAll(key, doctorJsonList.toArray(new String[0]));
    }

    @Override
    public int removeFollow(Long followId) {
        Long userId = tokenService.getLoginUser().getUserid();
        LambdaUpdateWrapper<DoctorRequest> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(DoctorRequest::getDoctorId, followId)
                .eq(DoctorRequest::getUserId, userId)
                .set(DoctorRequest::getFollowStatus, ACTIVE_NONE_STATUS);

        int updateCount = followMapper.update(null, lambdaUpdateWrapper);
        if (updateCount > 0) {
            String key = "followDoctors:" + userId;
            if (redisTemplate.hasKey(key)) {
                redisTemplate.delete(key);
            }
        }

        return updateCount;
    }
}
